/*================================================================
*   Copyright (C) 2020 Sangfor Ltd. All rights reserved.
*   
*   文件名称：select.hpp
*   创 建 者：Ann
*   创建日期：2020年05月20日
*   描    述：
*
================================================================*/

#pragma once
#include <stdio.h>
#include <unistd.h>
#include <sys/select.h>
#include <vector>

#include "tcpsvr.hpp"

class SelectSvr
{
    public:
        SelectSvr()
        {
            //清空
            FD_ZERO(&readfds_);
            max_fd_ = -1;
        }

        void AddFd(int fd)
        {
            //添加文件描述符
            FD_SET(fd, &readfds_);
            //更新最大文件描述符数值
            if(fd > max_fd_)
            {
                max_fd_ = fd;
            }
        }

        void DeleteFd(int fd)
        {
            //删除文件描述符
            FD_CLR(fd, &readfds_);

            //更新最大文件描述符数值
            //efor 0 1 2 3 4 5 6    == > 5
            //0 1 2 3 4 6
            //5 4 3 2 1 0  
            //6 5 4 3 2 1 0
            //从后往前遍历，找到第一个在可读事件集合当中的描述符就是最大的文件描述符
            for(int i = max_fd_; i >=0; i--)
            {
                if(!FD_ISSET(fd, &readfds_))
                {
                    continue;
                }
                max_fd_ = i;
                //break 是至关重要的
                break;
            }
        }

        bool SelectWait(std::vector<TcpSvr>* out)
        {
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 3000;

            fd_set tmp = readfds_;
            int ret = select(max_fd_ + 1, &tmp, NULL, NULL, &tv);
            if(ret < 0)
            {
                perror("select");
                return false;
            }
            else if(ret == 0)
            {
                //printf("select timeout\n");
                return false;
            }

            //正常情况
            for(int i = 0; i <= max_fd_; i++)
            {
                if(FD_ISSET(i, &tmp))
                {
                    //发生事件了，将文件描述符返回给调用者
                    TcpSvr ts;
                    ts.Setfd(i);
                    out->push_back(ts);
                }
            }
            return true;
        }
    private:
        //最大文件描述符数值
        int max_fd_;
        fd_set readfds_;
};
